package cn.com.nes.site.module.service;

import cn.com.nes.common.util.DouYinAPIUtils;
import cn.com.nes.common.util.ParameterUtil;
import cn.com.nes.mybatis.agent.system.entity.TUser;
import cn.com.nes.mybatis.agent.system.entity.UserAuthDouyin;
import cn.com.nes.mybatis.agent.system.entity.UserDouyin;
import cn.com.nes.mybatis.agent.system.entity.UserDouyinRelation;
import cn.com.nes.mybatis.agent.system.mapper.TUserMapper;
import cn.com.nes.mybatis.agent.system.mapper.UserAuthDouyinMapper;
import cn.com.nes.mybatis.agent.system.mapper.UserDouyinMapper;
import cn.com.nes.site.entity.DataReq;
import cn.com.nes.site.entity.PageData;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.Map;

/**
 * 抖音接入相关接口处理实现
 */
@Service
public class DouYinService {

    @Value("${client_key}")
    private String client_key;

    @Value("${client_secret}")
    private String client_secret;

    @Resource
    private UserAuthDouyinMapper userAuthDouyinMapper;

    @Resource
    private UserDouyinMapper userDouyinMapper;

    @Resource
    private TUserMapper userMapper;

    /**
     * 抖音授权
     * - 获取access_token
     * - 获取抖音用户信息
     * - 平台绑定用户
     * - 获取粉丝列表
     * - 获取关注列表
     */
    @Transactional(value = "transactionManager_newg", rollbackFor = Exception.class)
    public PageData saveAccess(DataReq req) throws Exception {
        PageData res = new PageData();
        // 获取授权码
        String code = ParameterUtil.getString(req, "code");
        if (StrUtil.isEmpty(code)) {
            return res.error(9, "请填写授权码 code");
        }

        // 用户ID
        String userId = req.getUinfo().getUuid();

        // 通过用户ID，查询平台用户表
        TUser user = userMapper.getUserInfoByUserId(userId);
        if (ObjectUtil.isEmpty(user)) {
            return res.error(9, "当前用户不存在，请先在平台注册");
        }

        // 判断当前平台用户是否绑定抖音用户。 -> 没有绑定，执行绑定操作。已绑定，判断是否需要更新授权
        if (StrUtil.isEmpty(user.getOpenIdDy())) {
            return bindDouYinUser(res, code, user);
        } else {
            return updateDouYinAuth(res, code, user);
        }
    }

    /**
     * 更新权限信息
     *
     * @param res
     * @param code 授权码
     * @param user 平台用户信息
     * @return
     * @throws Exception
     */
    private PageData updateDouYinAuth(PageData res, String code, TUser user) throws Exception {
        UserAuthDouyin authInfo = userAuthDouyinMapper.getAuthInfoByOpenId(user.getOpenIdDy());
        // 通过权限信息的修改时间，和当前时间计算差值，计算过期时间
        LocalDateTime modifyTime = authInfo.getModifyTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        Duration duration = Duration.between(modifyTime, LocalDateTime.now());
        long millis = duration.toMillis() / 1000;
        // 时间差值小于过期时间，不更新
        if (millis < authInfo.getExpiresIn()) {
            return res.success();
        }

        // 调用抖音AccessToken接口，获取AccessToken信息
        JSONObject AccessJson = DouYinAPIUtils.accessToken(code);
        if (ObjectUtil.isEmpty(AccessJson)) {
            throw new Exception("抖音授权接口调用失败，未获取到授权信息");
//            return res.error(9, "抖音授权接口调用失败，未获取到授权信息");
        }
        JSONObject data = AccessJson.getJSONObject("data");
        int error_code = data.getIntValue("error_code");
        String description = data.getString("description");
        if (error_code != 0) {
            throw new Exception("抖音授权接口调用失败, 原因：" + description);
//            return res.error(9, "抖音授权接口调用失败, 原因：" + description);
        }

        // 更新抖音权限信息
        authInfo.updateAuthInfo(data);
        authInfo.setModifyInfo(user.getId(), new Date());
        userAuthDouyinMapper.updateById(authInfo);
        return res.success();
    }

    /**
     * 绑定抖音用户信息，保存auth和user
     *
     * @param res
     * @param code 授权码
     * @param user 平台用户信息
     * @return
     * @throws Exception
     */
    private PageData bindDouYinUser(PageData res, String code, TUser user) throws Exception {
        // 调用抖音AccessToken接口，获取AccessToken信息
        JSONObject accessJson = DouYinAPIUtils.accessToken(code);
        if (ObjectUtil.isEmpty(accessJson)) {
            return res.error(9, "抖音授权接口调用失败，未获取到授权信息");
        }
        JSONObject authData = accessJson.getJSONObject("data");
        int error_code = authData.getIntValue("error_code");
        String description = authData.getString("description");
        if (error_code != 0) {
            System.out.println("error_code: " + error_code + " desc: " + description);
            return res.error(9, "抖音授权接口调用失败, 原因：" + description);
        }

        // 实例化抖音权限信息
        UserAuthDouyin authInfo = new UserAuthDouyin(authData);
        authInfo.setCreateInfo(user.getId(), new Date());
        authInfo.insertOrUpdate();

        // 调用抖音用户信息接口，获取用户信息
        JSONObject userJson = DouYinAPIUtils.userInfo(authInfo.getAccessToken(), authInfo.getOpenId());
        if (ObjectUtil.isEmpty(userJson)) {
            throw new Exception("抖音用户公开信息接口调用失败，未获取到用户公开信息");
//            return res.error(9, "抖音用户公开信息接口调用失败，未获取到用户公开信息");
        }
        JSONObject userData = userJson.getJSONObject("data");
        error_code = userData.getIntValue("error_code");
        description = userData.getString("description");
        if (error_code != 0) {
            throw new Exception("抖音用户公开信息接口调用失败，原因：" + description);
//            return res.error(9, "抖音用户信息接口调用失败, 原因：" + description);
        }

        // 实例化抖音用户信息
        UserDouyin userInfo = new UserDouyin(userData);
        userInfo.setCreateInfo(user.getId(), new Date());
        userInfo.insertOrUpdate();

        // 第一次绑定，需要向平台user表中设置抖音用户的openId
        user.setOpenIdDy(userInfo.getOpenId());
        user.setModifyInfo(user.getId(), new Date());
        user.insertOrUpdate();

        // 获取抖音粉丝列表
        Boolean has_more;
        int cursor = 0;
        do {
            JSONObject fansJson = DouYinAPIUtils.fansList(authInfo.getAccessToken(), authInfo.getOpenId(), cursor);
            JSONObject fansData = fansJson.getJSONObject("data");
            if (fansData.getIntValue("error_code") != 0) {
                throw new Exception("抖音粉丝列表接口调用失败，原因：" + fansData.getString("description"));
//                return res.error(9, "抖音粉丝列表接口调用失败, 原因：" + fansData.getString("description"));
            }
            has_more = fansData.getBooleanValue("has_more");
            cursor = fansData.getIntValue("cursor");
            int total = fansData.getIntValue("total");
            if (total > 0) {
                JSONArray list = fansData.getJSONArray("list");
                if (list.size() <= 0) {
                    break;
                }
                for (int i = 0; i < list.size(); i++) {
                    UserDouyin fanUser = list.getObject(i, UserDouyin.class);
                    fanUser.setCreateInfo(user.getId(), new Date());
                    fanUser.insertOrUpdate();

                    UserDouyinRelation relation = new UserDouyinRelation();
                    relation.setOpenId(authInfo.getOpenId());
                    relation.setFanOpenId(fanUser.getOpenId());
                    relation.insert();
                }
            }
        } while (has_more);


        // 获取抖音关注列表
        cursor = 0;
        do {
            JSONObject followingJson = DouYinAPIUtils.followingList(authInfo.getAccessToken(), authInfo.getOpenId(), cursor);
            JSONObject followingData = followingJson.getJSONObject("data");
            if (followingData.getIntValue("error_code") != 0) {
                throw new Exception("抖音粉丝列表接口调用失败，原因：" + followingData.getString("description"));
//                return res.error(9, "抖音关注列表接口调用失败, 原因：" + followingData.getString("description"));
            }
            has_more = followingData.getBooleanValue("has_more");
            cursor = followingData.getIntValue("cursor");

            JSONArray list = followingData.getJSONArray("list");
            if (ObjectUtil.isNull(list)) {
                break;
            }
            for (int i = 0; i < list.size(); i++) {
                UserDouyin followingUser = list.getObject(i, UserDouyin.class);
                followingUser.setCreateInfo(user.getId(), new Date());
                followingUser.insertOrUpdate();

                UserDouyinRelation relation = new UserDouyinRelation();
                relation.setOpenId(followingUser.getOpenId());
                relation.setFanOpenId(authInfo.getOpenId());
                relation.insert();
            }

        } while (has_more);

        return res.success();
    }

    /**
     * 获取 抖音权限信息
     *
     * @param req
     * @return
     * @throws Exception
     */
    public PageData getAccessToken(DataReq req) throws Exception {
        PageData res = new PageData();
        // 获取授权码
        String code = ParameterUtil.getString(req, "code");
        if (StrUtil.isEmpty(code)) {
            return res.error(9, "请填写授权码 code");
        }

        JSONObject accessToken = DouYinAPIUtils.accessToken(code);
        if (ObjectUtil.isEmpty(accessToken)) {
            return res.error(9, "授权接口调用失败");
        }
        JSONObject authData = accessToken.getJSONObject("data");
        int error_code = authData.getIntValue("error_code");
        String description = authData.getString("description");
        if (error_code != 0) {
            System.out.println("error_code: " + error_code + " desc: " + description);
            return res.error(9, "抖音授权接口调用失败, 原因：" + description);
        }
        System.out.println("接口返回： " + authData.toJSONString());
        Map<String, Object> data = JSONObject.parseObject(authData.toJSONString(), Map.class);
        res.setData(data);
        return res.success();
    }

    /**
     * 获取 抖音用户信息
     *
     * @param req
     * @return
     */
    public PageData getUserInfo(DataReq req) throws Exception {
        PageData res = new PageData();

        // 用户ID
        String userId = req.getUinfo().getUuid();

        // 通过用户ID，查询平台用户表
        TUser user = userMapper.getUserInfoByUserId(userId);
        if (ObjectUtil.isEmpty(user)) {
            return res.error(9, "当前用户不存在，请先在平台注册");
        }

        // 根据抖音用户唯一标识，查询用户授权信息
//        UserAuthDouyin authInfo = userAuthDouyinMapper.getAuthInfoByOpenId(user.getOpenIdDy());
        String access_token = ParameterUtil.getString(req, "access_token");
        String open_id = ParameterUtil.getString(req, "open_id");

        JSONObject userInfo = DouYinAPIUtils.userInfo(access_token, open_id);
        if (ObjectUtil.isEmpty(userInfo)) {
            return res.error(9, "获取用户公开信息接口调用失败");
        }
        JSONObject userData = userInfo.getJSONObject("data");
        int error_code = userData.getIntValue("error_code");
        String description = userData.getString("description");
        if (error_code != 0) {
            System.out.println("error_code: " + error_code + " desc: " + description);
            return res.error(9, "获取用户公开信息接口调用失败, 原因：" + description);
        }
        System.out.println("接口返回： " + userData.toJSONString());
        Map<String, Object> data = JSONObject.parseObject(userData.toJSONString(), Map.class);
        res.setData(data);
        return res.success();
    }

    /**
     * 获取 抖音粉丝列表
     *
     * @param req
     * @return
     * @throws Exception
     */
    public PageData getFansList(DataReq req) throws Exception {
        PageData res = new PageData();

        // 用户ID
        String userId = req.getUinfo().getUuid();

        // 通过用户ID，查询平台用户表
        TUser user = userMapper.getUserInfoByUserId(userId);
        if (ObjectUtil.isEmpty(user)) {
            return res.error(9, "当前用户不存在，请先在平台注册");
        }

        // 根据抖音用户唯一标识，查询用户授权信息
//        UserAuthDouyin authInfo = userAuthDouyinMapper.getAuthInfoByOpenId(user.getOpenIdDy());
        String access_token = ParameterUtil.getString(req, "access_token");
        String open_id = ParameterUtil.getString(req, "open_id");
        int cursor = ParameterUtil.getInteger(req, "cursor");

        JSONObject fansList = DouYinAPIUtils.fansList(access_token, open_id, cursor);
        if (ObjectUtil.isEmpty(fansList)) {
            return res.error(9, "获取粉丝列表接口调用失败");
        }
        JSONObject fansData = fansList.getJSONObject("data");
        int error_code = fansData.getIntValue("error_code");
        String description = fansData.getString("description");
        if (error_code != 0) {
            System.out.println("error_code: " + error_code + " desc: " + description);
            return res.error(9, "获取粉丝列表接口调用失败, 原因：" + description);
        }
        System.out.println("接口返回： " + fansData.toJSONString());
        Map<String, Object> data = JSONObject.parseObject(fansData.toJSONString(), Map.class);
        res.setData(data);
        return res.success();
    }

    /**
     * 获取 抖音关注列表
     *
     * @param req
     * @return
     * @throws Exception
     */
    public PageData getFollowsList(DataReq req) throws Exception {
        PageData res = new PageData();

        // 用户ID
        String userId = req.getUinfo().getUuid();

        // 通过用户ID，查询平台用户表
        TUser user = userMapper.getUserInfoByUserId(userId);
        if (ObjectUtil.isEmpty(user)) {
            return res.error(9, "当前用户不存在，请先在平台注册");
        }

        // 根据抖音用户唯一标识，查询用户授权信息
//        UserAuthDouyin authInfo = userAuthDouyinMapper.getAuthInfoByOpenId(user.getOpenIdDy());
        String access_token = ParameterUtil.getString(req, "access_token");
        String open_id = ParameterUtil.getString(req, "open_id");
        int cursor = ParameterUtil.getInteger(req, "cursor");

        JSONObject followingList = DouYinAPIUtils.followingList(access_token, open_id, cursor);
        if (ObjectUtil.isEmpty(followingList)) {
            return res.error(9, "获取粉丝列表接口调用失败");
        }
        JSONObject followingData = followingList.getJSONObject("data");
        int error_code = followingData.getIntValue("error_code");
        String description = followingData.getString("description");
        if (error_code != 0) {
            System.out.println("error_code: " + error_code + " desc: " + description);
            return res.error(9, "获取粉丝列表接口调用失败, 原因：" + description);
        }
        System.out.println("接口返回： " + followingData.toJSONString());
        Map<String, Object> data = JSONObject.parseObject(followingData.toJSONString(), Map.class);
        res.setData(data);
        return res.success();
    }

    /**
     * 抖音用户粉丝判断
     *
     * @param req
     * @return
     */
    public PageData fansCheck(DataReq req) throws Exception {
        PageData res = new PageData();

        // 用户ID
        String userId = req.getUinfo().getUuid();

        // 通过用户ID，查询平台用户表
        TUser user = userMapper.getUserInfoByUserId(userId);
        if (ObjectUtil.isEmpty(user)) {
            return res.error(9, "当前用户不存在，请先在平台注册");
        }

        // 根据抖音用户唯一标识，查询用户授权信息
//        UserAuthDouyin authInfo = userAuthDouyinMapper.getAuthInfoByOpenId(user.getOpenIdDy());
        String access_token = ParameterUtil.getString(req, "access_token");
        String open_id = ParameterUtil.getString(req, "open_id");
        String follow_open_id = ParameterUtil.getString(req, "follow_open_id");

        JSONObject fansCheck = DouYinAPIUtils.fansCheck(access_token, open_id, follow_open_id);
        JSONObject fansCheckData = fansCheck.getJSONObject("data");
        int error_code = fansCheckData.getIntValue("error_code");
        String description = fansCheckData.getString("description");
        if (error_code != 0) {
            System.out.println("error_code: " + error_code + " desc: " + description);
            return res.error(9, "获取粉丝列表接口调用失败, 原因：" + description);
        }
        System.out.println("接口返回： " + fansCheckData.toJSONString());
        Map<String, Object> data = JSONObject.parseObject(fansCheckData.toJSONString(), Map.class);
        res.setData(data);
        return res.success();
    }

    /**
     * 获取 抖音用户视频列表
     *
     * @param req
     * @return
     * @throws Exception
     */
    public PageData videoList(DataReq req) throws Exception {
        PageData res = new PageData();

        // 用户ID
        String userId = req.getUinfo().getUuid();

        // 通过用户ID，查询平台用户表
        TUser user = userMapper.getUserInfoByUserId(userId);
        if (ObjectUtil.isEmpty(user)) {
            return res.error(9, "当前用户不存在，请先在平台注册");
        }

        // 根据抖音用户唯一标识，查询用户授权信息
//        UserAuthDouyin authInfo = userAuthDouyinMapper.getAuthInfoByOpenId(user.getOpenIdDy());

        String access_token = ParameterUtil.getString(req, "access_token");
        String open_id = ParameterUtil.getString(req, "open_id");
        int cursor = ParameterUtil.getInteger(req, "cursor");

        JSONObject videoList = DouYinAPIUtils.videoList(access_token, open_id, cursor);
        JSONObject videoListData = videoList.getJSONObject("data");
        int error_code = videoListData.getIntValue("error_code");
        String description = videoListData.getString("description");
        if (error_code != 0) {
            System.out.println("error_code: " + error_code + " desc: " + description);
            return res.error(9, "获取粉丝列表接口调用失败, 原因：" + description);
        }
        System.out.println("接口返回： " + videoListData.toJSONString());
        Map<String, Object> data = JSONObject.parseObject(videoListData.toJSONString(), Map.class);
        res.setData(data);
        return res.success();
    }

    /**
     * 获取 特定视频的视频数据
     *
     * @param req
     * @return
     * @throws Exception
     */
    public PageData videoData(DataReq req) throws Exception {
        PageData res = new PageData();

        // 用户ID
        String userId = req.getUinfo().getUuid();

        // 通过用户ID，查询平台用户表
        TUser user = userMapper.getUserInfoByUserId(userId);
        if (ObjectUtil.isEmpty(user)) {
            return res.error(9, "当前用户不存在，请先在平台注册");
        }

        String access_token = ParameterUtil.getString(req, "access_token");
        String open_id = ParameterUtil.getString(req, "open_id");
        String[] item_ids = ParameterUtil.getStringArray(req, "item_ids");

        JSONObject videoDataJson = DouYinAPIUtils.videoData(access_token, open_id, item_ids);
        JSONObject videoListData = videoDataJson.getJSONObject("data");
        int error_code = videoListData.getIntValue("error_code");
        String description = videoListData.getString("description");
        if (error_code != 0) {
            System.out.println("error_code: " + error_code + " desc: " + description);
            return res.error(9, "获取粉丝列表接口调用失败, 原因：" + description);
        }
        System.out.println("接口返回： " + videoListData.toJSONString());
        Map<String, Object> data = JSONObject.parseObject(videoListData.toJSONString(), Map.class);
        res.setData(data);
        return res.success();
    }

    /**
     * 关键词视频搜索
     *
     * @param req
     * @return
     * @throws Exception
     */
    public PageData videoSearch(DataReq req) throws Exception {
        PageData res = new PageData();

        // 用户ID
        String userId = req.getUinfo().getUuid();

        // 通过用户ID，查询平台用户表
        TUser user = userMapper.getUserInfoByUserId(userId);
        if (ObjectUtil.isEmpty(user)) {
            return res.error(9, "当前用户不存在，请先在平台注册");
        }

        String access_token = ParameterUtil.getString(req, "access_token");
        String open_id = ParameterUtil.getString(req, "open_id");
        int cursor = ParameterUtil.getInteger(req, "cursor");
        String keyword = ParameterUtil.getString(req, "keyword");

        JSONObject videoDataJson = DouYinAPIUtils.videoSearch(access_token, open_id, cursor, keyword);
        JSONObject videoListData = videoDataJson.getJSONObject("data");
        int error_code = videoListData.getIntValue("error_code");
        String description = videoListData.getString("description") + "," + videoDataJson.getJSONObject("extra").getString("sub_description");
        if (error_code != 0) {
            System.out.println("error_code: " + error_code + " desc: " + description);
            return res.error(9, "关键词视频搜索接口调用失败, 原因：" + description);
        }
        System.out.println("接口返回： " + videoListData.toJSONString());
        Map<String, Object> data = JSONObject.parseObject(videoListData.toJSONString(), Map.class);
        res.setData(data);
        return res.success();
    }

    /**
     * 获取 关键词视频评论列表
     *
     * @param req
     * @return
     * @throws Exception
     */
    public PageData videoSearchConmment(DataReq req) throws Exception {
        PageData res = new PageData();

        // 用户ID
        String userId = req.getUinfo().getUuid();

        // 通过用户ID，查询平台用户表
        TUser user = userMapper.getUserInfoByUserId(userId);
        if (ObjectUtil.isEmpty(user)) {
            return res.error(9, "当前用户不存在，请先在平台注册");
        }

        String client_token = ParameterUtil.getString(req, "client_token");
        String sec_item_id = ParameterUtil.getString(req, "sec_item_id");
        int cursor = ParameterUtil.getInteger(req, "cursor");

        JSONObject videoDataJson = DouYinAPIUtils.videoSearchCommentList(client_token, sec_item_id, cursor);
        JSONObject videoListData = videoDataJson.getJSONObject("data");
        int error_code = videoListData.getIntValue("error_code");
        String description = videoListData.getString("description");
        if (error_code != 0) {
            System.out.println("error_code: " + error_code + " desc: " + description);
            return res.error(9, "获取抖音关键词视频评论列表接口调用失败, 原因：" + description);
        }
        System.out.println("接口返回： " + videoListData.toJSONString());
        Map<String, Object> data = JSONObject.parseObject(videoListData.toJSONString(), Map.class);
        res.setData(data);
        return res.success();
    }

}
